#include "lcd.h"
#include "lcd_init.h"
#include "lcd_font.h"
#include "typedef.h"
#include "gd25q64.h"

/******************************************************************************
	  函数说明：在指定区域填充颜色
	  入口数据：xsta,ysta   起始坐标
				xend,yend   终止坐标
								color       要填充的颜色
	  返回值：  无
******************************************************************************/
void LCD_Fill(u16 xsta, u16 ysta, u16 xend, u16 yend, u16 color)
{
	u16 i, j;
	LCD_Address_Set(xsta, ysta, xend - 1, yend - 1); // 设置显示范围
	for (i = ysta; i < yend; i++)
	{
		for (j = xsta; j < xend; j++)
		{
			LCD_WR_DATA(color);
		}
	}
}

void LCD_Clear(u16 color) {
	LCD_Fill(0, 0, LCD_W, LCD_H, color);
}

/******************************************************************************
	  函数说明：在指定位置画点
	  入口数据：x,y 画点坐标
				color 点的颜色
	  返回值：  无
******************************************************************************/
void LCD_DrawPoint(u16 x, u16 y, u16 color)
{
	LCD_Address_Set(x, y, x, y); // 设置光标位置
	LCD_WR_DATA(color);
}

/******************************************************************************
	  函数说明：画线
	  入口数据：x1,y1   起始坐标
				x2,y2   终止坐标
				color   线的颜色
	  返回值：  无
******************************************************************************/
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2, u16 color)
{
	u16 t;
	int xerr = 0, yerr = 0, delta_x, delta_y, distance;
	int incx, incy, uRow, uCol;
	delta_x = x2 - x1; // 计算坐标增量
	delta_y = y2 - y1;
	uRow = x1; // 画线起点坐标
	uCol = y1;
	if (delta_x > 0) 
	{
		incx = 1; // 设置单步方向
	}
	else if (delta_x == 0)
	{
		incx = 0; // 垂直线
	}
	else
	{
		incx = -1;
		delta_x = -delta_x;
	}
	if (delta_y > 0)
	{
		incy = 1;
	}	
	else if (delta_y == 0)
	{
		incy = 0; // 水平线
	}
	else
	{
		incy = -1;
		delta_y = -delta_x;
	}
	if (delta_x > delta_y)
	{
		distance = delta_x; // 选取基本增量坐标轴
	}
	else
	{
		distance = delta_y;
	}
		
	for (t = 0; t < distance + 1; t++)
	{
		LCD_DrawPoint(uRow, uCol, color); // 画点
		xerr += delta_x;
		yerr += delta_y;
		if (xerr > distance)
		{
			xerr -= distance;
			uRow += incx;
		}
		if (yerr > distance)
		{
			yerr -= distance;
			uCol += incy;
		}
	}
}

/******************************************************************************
	  函数说明：画矩形
	  入口数据：x1,y1   起始坐标
				x2,y2   终止坐标
				color   矩形的颜色
	  返回值：  无
******************************************************************************/
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2, u16 color)
{
	LCD_DrawLine(x1, y1, x2, y1, color);
	LCD_DrawLine(x1, y1, x1, y2, color);
	LCD_DrawLine(x1, y2, x2, y2, color);
	LCD_DrawLine(x2, y1, x2, y2, color);
}

/******************************************************************************
	  函数说明：画圆
	  入口数据：x0,y0   圆心坐标
				r       半径
				color   圆的颜色
	  返回值：  无
******************************************************************************/
void Draw_Circle(u16 x0, u16 y0, u8 r, u16 color)
{
	u16 a, b;
	a = 0;
	b = r;
	while (a <= b)
	{
		LCD_DrawPoint(x0 - b, y0 - a, color); // 3
		LCD_DrawPoint(x0 + b, y0 - a, color); // 0
		LCD_DrawPoint(x0 - a, y0 + b, color); // 1
		LCD_DrawPoint(x0 - a, y0 - b, color); // 2
		LCD_DrawPoint(x0 + b, y0 + a, color); // 4
		LCD_DrawPoint(x0 + a, y0 - b, color); // 5
		LCD_DrawPoint(x0 + a, y0 + b, color); // 6
		LCD_DrawPoint(x0 - b, y0 + a, color); // 7
		a++;
		if ((a * a + b * b) > (r * r)) // 判断要画的点是否过远
		{
			b--;
		}
	}
}

/******************************************************************************
      函数说明：显示单个字符
      入口数据：x,y显示坐标
                num 要显示的字符
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值：  无
******************************************************************************/
void LCD_ShowChar(u16 x,u16 y,u8 num,u16 fc,u16 bc,u8 sizey,u8 mode)
{
	u8 temp,sizex,t;
	u16 i,TypefaceNum;//一个字符所占字节大小
	u16 x0=x;
	sizex=sizey/2;
	TypefaceNum=sizex/8*sizey;
	num=num-' ';    //得到偏移后的值
	LCD_Address_Set(x,y,x+sizex-1,y+sizey-1);  //设置光标位置 
	for(i=0;i<TypefaceNum;i++)
	{ 
		if(sizey==16)
		{
			temp=ascii_1608[num][i];		       //调用8x16字体
		}
		else if(sizey==32)
		{
			temp=ascii_3216[num][i];		 //调用16x32字体
		}
		else 
		{
			return;
		}
		for(t=0;t<8;t++)
		{
			if(!mode)//非叠加模式
			{
				if(temp&(0x01<<t))
				{
					LCD_WR_DATA(fc);
				}
				else 
				{
					LCD_WR_DATA(bc);
				}
			}
			else//叠加模式
			{
				if(temp&(0x01<<t))
				{
					LCD_DrawPoint(x,y,fc);//画一个点
				}
				x++;
				if((x-x0)==sizex)
				{
					x=x0;
					y++;
					break;
				}
			}
		}
	}   	 	  
}


/******************************************************************************
      函数说明：显示字符串
      入口数据：x,y显示坐标
                *p 要显示的字符串
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值：  无
******************************************************************************/
void LCD_ShowString(u16 x,u16 y,const u8 *p,u16 fc,u16 bc,u8 sizey,u8 mode)
{         
	while(*p!='\0')
	{       
		LCD_ShowChar(x,y,*p,fc,bc,sizey,mode);
		x+=sizey/2;
		p++;
	}  
}


/******************************************************************************
      函数说明：显示数字
      入口数据：m底数，n指数
      返回值：  无
******************************************************************************/
u32 mypow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;
	return result;
}


/******************************************************************************
      函数说明：显示整数变量
      入口数据：x,y显示坐标
                num 要显示整数变量
                len 要显示的位数
                fc 字的颜色
                bc 字的背景色
      返回值：  无
******************************************************************************/
void LCD_ShowIntNum(u16 x,u16 y,u16 num,u8 len,u16 fc,u16 bc)
{         	
	u8 t,temp;
	u8 enshow=0;
	for(t=0;t<len;t++)
	{
		temp=(num/mypow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				LCD_ShowAsc1224(x+t*ASCII_X_S,y,' ',fc,bc);
				continue;
			}
			else 
			{
				enshow=1; // 当出现第一个不是0的位后，后面的每一个0都要显示为0
			}
		 	 
		}
	 	LCD_ShowAsc1224(x+t*ASCII_X_S,y,temp+48,fc,bc);
	}
} 


/******************************************************************************
      函数说明：显示整数变量高位补0
      入口数据：x,y显示坐标
                num 要显示整数变量
                len 要显示的位数
                fc 字的颜色
                bc 字的背景色
      返回值：  无
******************************************************************************/
void LCD_ShowIntNumWithZeroLeft(u16 x,u16 y,u16 num,u8 len,u16 fc,u16 bc)
{         	
	u8 t,temp;
	for(t=0;t<len;t++)
	{
		temp=(num/mypow(10,len-t-1))%10;
	 	LCD_ShowAsc1224(x+t*ASCII_X_S,y,temp+48,fc,bc);
	}
} 

/******************************************************************************
      函数说明：显示两位小数变量
      入口数据：x,y显示坐标
                num 要显示小数变量
                len 要显示的位数
                fc 字的颜色
                bc 字的背景色
                sizey 字号
      返回值：  无
******************************************************************************/
void LCD_ShowFloatNum1(u16 x,u16 y,float num,u8 len,u16 fc,u16 bc,u8 sizey)
{         	
	u8 t,temp,sizex;
	u16 num1;
	sizex=sizey/2;
	num1=num*100;
	for(t=0;t<len;t++)
	{
		temp=(num1/mypow(10,len-t-1))%10;
		if(t==(len-2))
		{
			LCD_ShowChar(x+(len-2)*sizex,y,'.',fc,bc,sizey,0);
			t++;
			len+=1;
		}
	 	LCD_ShowChar(x+t*sizex,y,temp+48,fc,bc,sizey,0);
	}
}

/* 从GD25Q64中获取某汉字的字模
   参数gbk：是汉字的GBK码
   参数rec_data：字模会被读到这个数组*/
void GBK_Fetch(unsigned char* gbk, unsigned char* rec_data)
{
	unsigned char GBKH,GBKL;
	unsigned long addr;
	
	GBKH=*gbk;
	GBKL=*(gbk+1);
	
	if((GBKH>0XFE)||(GBKH<0x81))
	{
		return;
	}
	GBKH=GBKH-0X81;
	GBKL=GBKL-0X40;
	
	addr=((unsigned long)GBKH*192+GBKL)*GBK_LEN+ GBK_START;
	GD25Q64_Read(rec_data, addr, GBK_LEN);
}

/* 液晶屏显示一个24*24像素的汉字
   参数x y；是液晶屏的坐标
   参数gbk：是汉字的GBK码*/
void LCD_ShowGBK(unsigned int x, unsigned int y, unsigned char* gbk, u16 fc,u16 bc)
{
	unsigned int i,j;
	unsigned char temp;
	unsigned char xdata rec_data[GBK_LEN];
	
	GBK_Fetch(gbk, rec_data);
	
	LCD_Address_Set(x,y,x+23,y+23);
	LCD_WR_REG(0x2C);
	
	for(i=0;i<72;i++)
	{
		temp = rec_data[i];
		for(j=0;j<8;j++)
		{
			if(temp&0x80)
				LCD_WR_DATA(fc);
			else
				LCD_WR_DATA(bc);
			temp=temp<<1;
		}
	}
}

void LCD_ShowStrMidx(unsigned int y, unsigned char *p, u16 fc,u16 bc) {
	unsigned int x,len;
	unsigned char *temp;

	temp = p;
	len = 0;
	x = 0;

	while(*temp!='\0')	// 如果没有结束
	{       
		if(*temp>0x80)//如果是中文
		{
			len+=24;
			temp+=2;
		}
		else	   //如果是英文
		{
			len+=12;
			temp++;
		}
	}  

	x = (LCD_W - len) / 2;
	LCD_ShowStr(x, y, p, fc, bc);

}

/*********************************************/
/* 函数功能：显示字符串（中文和英文）        */
/* 入口参数：x,y: 坐标                     */
/*          *p:字符串                     */
/*          fc:字符颜色                     */
/*          bc:背景颜色                     */
/*********************************************/
void LCD_ShowStr(unsigned int x, unsigned int y, unsigned char *p, u16 fc,u16 bc)
{         
	while(*p!='\0')	// 如果没有结束
	{       
		if(*p>0x80)//如果是中文
		{
			LCD_ShowGBK24(x, y, p, fc, bc);
			x+=24;
			p+=2;
		}
		else	   //如果是英文
		{
			LCD_ShowAsc1224(x,y,*p, fc, bc);
			x+=12;
			p++;
		}
	}  
}


/* 显示一张图片 */
void LCD_ShowPic(unsigned char n)
{
	/* 定义局部变量 */
	unsigned long pic_add=IMG_START+n*IMG_LEN;   // 从GD25Q64的这个地址开始读取第一张图片
	unsigned char xdata pic_buf[640]; // 每次从GD25Q64中读640个字节
	unsigned int i,j;
	
	/* 开辟液晶屏内存 */
	LCD_Address_Set(0, 0, 319, 239);
	LCD_WR_REG(0x2C);
	
	/* 开始画图 */
	for(j=0; j<240; j++) // 
	{
		GD25Q64_Read(pic_buf, pic_add, 640);  
		for(i=0; i<640; i+=2)
		{
			LCD_WR_DATA(((unsigned int)pic_buf[i]<<8)+pic_buf[i+1]);
		}
		pic_add+=640;
	}
}

/* 液晶屏显示12*24像素的英文Ascii码 */
void LCD_ShowAsc1224(unsigned int x, unsigned int y, unsigned char asc, u16 fc, u16 bc)
{
	unsigned int i,j;
	unsigned char xdata temp, asc_buf[48];
	
	asc = asc - 0x20;
	GD25Q64_Read(asc_buf, asc*48U, 48); 	
	
	LCD_Address_Set(x,y,x+11,y+23);
	LCD_WR_REG(0x2C);

	for(i=0;i<48;i++)
	{
		temp = asc_buf[i];
		for(j=0;j<8;j++)
		{
			if(temp&0x80)
				LCD_WR_DATA(fc);
			else
				LCD_WR_DATA(bc);
			temp=temp<<1;
		}
		i++;
		temp = asc_buf[i];
		for(j=0;j<4;j++)
		{
			if(temp&0x80)
				LCD_WR_DATA(fc);
			else
				LCD_WR_DATA(bc);
			temp=temp<<1;
		}
	}
}

/* 液晶屏显示16*24像素的英文Ascii码 */
void LCD_ShowAsc1624(unsigned int x, unsigned int y, unsigned char num, u16 fc, u16 bc)
{
	unsigned int i,j;
	unsigned char xdata temp, num_buf[48];
	
	GD25Q64_Read(num_buf, 6000+num*48U, 48); 	
	
	LCD_Address_Set(x,y,x+15,y+23);
	LCD_WR_REG(0x2C);
	
	for(i=0;i<48;i++)
	{
		temp = num_buf[i];
		for(j=0;j<8;j++)
		{
			if(temp&0x80)
				LCD_WR_DATA(fc);
			else
				LCD_WR_DATA(bc);
			temp=temp<<1;
		}
	}
}


/* 液晶屏显示24*24像素的GBK字符 */
void LCD_ShowGBK24(unsigned int x, unsigned int y, unsigned char *gbk, u16 fc,u16 bc)
{
	unsigned int xdata i,j;
	unsigned char xdata temp;
	unsigned char xdata rec_data[72];
	unsigned char xdata GBKH,GBKL;
	unsigned long xdata addr;
	
	GBKH=*gbk;
	GBKL=*(gbk+1);
	
	if((GBKH>0XFE)||(GBKH<0x81))
	{
		return; // GBK码解析错误 返回
	}
	GBKH=GBKH-0X81;
	GBKL=GBKL-0X40;
	
	addr=((unsigned long)GBKH*192+GBKL)*GBK_LEN+GBK_START;
	GD25Q64_Read(rec_data, addr, GBK_LEN); 	
	
	LCD_Address_Set(x,y,x+23,y+23);
	LCD_WR_REG(0x2C);
	
	for(i=0;i<72;i++)
	{
		temp = rec_data[i];
		for(j=0;j<8;j++)
		{
			if(temp&0x80)
				LCD_WR_DATA(fc);
			else
				LCD_WR_DATA(bc);
			temp=temp<<1;
		}
	}
}